package com.jzsm.common.aspectj;

import cn.hutool.core.util.IdUtil;
import com.jzsm.modules.sender.bo.message.MessageBo;
import com.jzsm.modules.sender.pojo.PushChannelAccount;
import com.jzsm.modules.sender.pojo.PushLog;
import com.jzsm.modules.sender.dao.PushLogDao;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

@Aspect
@Component
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SenderLogAnnoAspectj {
    final PushLogDao pushLogDao;

    /**
     * 拦截发送成功的信息
     *
     * @param joinPoint
     */
    @AfterReturning(
            pointcut = "execution(* com.jzsm.modules.sender.senderService.IMessageSender.sendMessage(..))",
            returning = "result")
    public void afterReturningMethodExecution(JoinPoint joinPoint, String result) {
        // 插入日志
        runAsync(() -> insertLog(PushLog.StatusEnum.SUCCESS, joinPoint.getArgs(), result));
    }

    /**
     * 拦截发送失败的信息
     *
     * @param joinPoint
     */
    @AfterThrowing(
            pointcut = "execution(* com.jzsm.modules.sender.senderService.IMessageSender.sendMessage(..))",
            throwing = "exception")
    public void afterThrowingMethodExecution(JoinPoint joinPoint, Exception exception) {
        // 插入日志
        runAsync(() -> insertLog(PushLog.StatusEnum.ERROR, joinPoint.getArgs(), exception.getMessage()));
    }

    /**
     * 插入日志
     *
     * @param statusEnum 状态枚举
     * @param args       方法参数
     * @param result     方法返回值
     * @return
     */
    private int insertLog(PushLog.StatusEnum statusEnum, Object[] args, String result) {
        String message;
        String businessId = "";
        PushChannelAccount account;
        /*
          存在 重载方法
         */
        if (args[0] instanceof MessageBo) {
            MessageBo arg = (MessageBo) args[0];
            message = arg.getMessage();
            businessId = arg.getBusinessId();
            account = arg.getAccount();
        } else {
            message = (String) args[0];
            account = (PushChannelAccount) args[1];
        }

        PushLog pushLog = new PushLog().setId(IdUtil.getSnowflakeNextIdStr())
                .setBusinessId(businessId).setContent(message)
                .setChannelAccountId(account.getId())
                .setResponse(result)
                .setStatus(statusEnum.getValue());
        // 执行插入
        return pushLogDao.insert(pushLog);
    }

    private CompletableFuture<Integer> runAsync(Supplier<Integer> supplier) {
        return CompletableFuture.supplyAsync(supplier).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });
    }
}
